package top.lingkang.mm.orm;

import org.apache.ibatis.annotations.*;
import top.lingkang.mm.annotation.MagicMapper;

import java.util.Collection;
import java.util.List;

/**
 * mapper 的基础增删查改
 *
 * @author lingkang
 * Created by 2024/3/11
 */
@Mapper
@MagicMapper
public interface BaseMapper<T> {
    /**
     * 查询所有，没有结果时返回空 List
     */
    @Select(BaseMapperSql.selectAll)
    @Lang(BaseMapperDriver.class)
    List<T> selectAll();

    /**
     * 根据id查询
     *
     * @param id 主键id，id的值，并非entity实体对象，例如 int、String、Date等类型值
     * @return 实体对象
     */
    @Select(BaseMapperSql.selectById)
    @Lang(BaseMapperDriver.class)
    T selectById(@Param(BaseMapperSql.param_id) Object id);

    /**
     * 根据id集合in查询
     * <pre>
     * {@code
     * List<UserEntity> selectByIds = mapper.selectInIds(Arrays.asList("1", "19951219"));
     * log.info("selectByIds: {}", selectByIds);
     * }
     * </pre>
     *
     * @param ids id数组，并非entity实体对象，参入应该是 int、String、Date等类型数组值
     * @return 实体对象
     * @since 1.1.0
     */
    @Select(BaseMapperSql.selectInIds)
    @Lang(BaseMapperDriver.class)
    List<T> selectInIds(@Param(BaseMapperSql.param_id_3) Collection<?> ids);

    /**
     * 查询表，根据条件
     * <pre>
     * {@code
     *         UserMapper mapper = mapperManage.getMapper(UserMapper.class);
     *         List<UserEntity> list = mapper.selectByQuery(new Query().gt("id", 1)); // 大于 >
     *         System.out.println("selectByQuery: " + list);
     *         list = mapper.selectByQuery(new Query().le("id", 1));  // 小于等于 <=
     *         System.out.println("selectByQuery: " + list);
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @return List<Entity>，没有结果时返回空 List
     * @since 1.1.0
     */
    @Select(BaseMapperSql.selectByQuery)
    @Lang(BaseMapperDriver.class)
    List<T> selectByQuery(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 在分页中使用此方法将会报错
     * <pre>
     * {@code
     *         // 若返回多个结果会报错，所以添加 limit 1
     *         entity = mapper.selectByQueryOne(new Query().gt("id", 1).sql("limit 1"));  //  大于 >
     *         log.info("selectByQueryOne: {}", entity);
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @return 结果的实体对象
     * @since 1.1.0
     */
    @Select(BaseMapperSql.selectByQueryOne)
    @Lang(BaseMapperDriver.class)
    T selectByQueryOne(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 查询表数据总行数
     *
     * @return 总行数
     */
    @Select(BaseMapperSql.selectCount)
    @Lang(BaseMapperDriver.class)
    long selectCount();

    /**
     * 根据条件查询查询总数，可以针对无id对象实体类
     * <pre>
     * {@code
     *         UserMapper mapper = mapperManage.getMapper(UserMapper.class);
     *         long total = mapper.selectCountByQuery(new Query().gt("id", 1)); // 大于 >
     *         log.info("total: {}", total);
     *         total = mapper.selectCountByQuery(new Query().le("id", 1));  // 小于等于 <=
     *         log.info("total: {}", total);
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @return count总数，必定是long型
     * @since 1.1.0
     */
    @Select(BaseMapperSql.selectCountByQuery)
    @Lang(BaseMapperDriver.class)
    long selectCountByQuery(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 查询指定列，并返回指定结果，例如：
     * <pre>
     * {@code
     * UserMapper userMapper = mapperManage.getMapper(UserMapper.class);
     * List<Long> list = userMapper.selectColumn(
     *         new QueryColumn(Long.class, "id")
     *                 .gt("id", 1) // 大于1 的id列
     * );
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @param <E>   结果对象类
     * @return 结果列表
     */
    @Select(BaseMapperSql.selectColumn)
    @Lang(BaseMapperDriver.class)
    <E> List<E> selectColumn(@Param(BaseMapperSql.param_q2) QueryColumn query);

    /**
     * 查询指定列，并返回一行结果；若返回多个结果时，将会报错；在分页中使用此方法将会报错
     * <pre>
     * {@code
     *     Long result = userMapper.selectColumnOne(
     *                 new QueryColumn(Long.class, "id").sql("limit 1"));
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @param <E>   结果对象类
     * @return 结果对象，结果是多行时抛出异常：{@link org.apache.ibatis.exceptions.TooManyResultsException}
     */
    @Select(BaseMapperSql.selectColumnOne)
    @Lang(BaseMapperDriver.class)
    <E> E selectColumnOne(@Param(BaseMapperSql.param_q2) QueryColumn query);

    /**
     * 判断是否存在
     *
     * @param id 主键id，id的值，并非entity实体对象，例如 int、String、Date等类型值
     * @return true：存在；false：不存在
     */
    @Select(BaseMapperSql.existsById)
    @Lang(BaseMapperDriver.class)
    boolean existsById(@Param(BaseMapperSql.param_id) Object id);

    /**
     * 根据实体对象，判断是否存在，实体对象必须存在@Id主键
     * <pre>
     * {@code
     *  UserEntity entity = new UserEntity();
     *  entity.setId(1L);
     *  boolean exists = userMapper.existsByEntity(entity);
     *  System.out.println("存在：" + exists);
     * }
     * </pre>
     *
     * @param entity 实体对象
     * @return true：存在；false：不存在
     * @since 1.1.0
     */
    @Select(BaseMapperSql.existsByEntity)
    @Lang(BaseMapperDriver.class)
    boolean existsByEntity(@Param(BaseMapperSql.param_id_2) T entity);

    /**
     * 根据条件查询数据是否存在，可以针对无id对象实体类
     *
     * <pre>
     * {@code
     *         UserMapper mapper = mapperManage.getMapper(UserMapper.class);
     *         boolean has = mapper.existsByQuery(new Query().eq("id", 1));
     *         System.out.println("exists: " + has);
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @return 存在：true；不存在：false
     * @since 1.1.0
     */
    @Select(BaseMapperSql.existsByQuery)
    @Lang(BaseMapperDriver.class)
    boolean existsByQuery(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 创建查询，例如：
     * <pre>
     * {@code
     * // 查询id为 1 的实体对象
     * List<UserEntity> list = mapper.createQuery(new Query().eq("id", 1))
     * }
     * </pre>
     *
     * @param query 查询条件，比较符可以参考：{@link Condition}
     * @return 结果列表
     */
    @Select(BaseMapperSql.createQuery)
    @Lang(BaseMapperDriver.class)
    List<T> createQuery(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 插入数据
     *
     * @param entity 实体对象
     * @return 受影响的行数
     */
    @Insert(BaseMapperSql.insert)
    @Lang(BaseMapperDriver.class)
    @Options(useGeneratedKeys = true)
    int insert(@Param(BaseMapperSql.magic_base_e) T entity);

    /**
     * 批量插入数据，例如
     * <pre>
     * {@code
     *         List<UserEntity> list = new ArrayList<>();
     *         UserEntity user = new UserEntity();
     *         user.setId(System.currentTimeMillis());
     *         UserEntity user1 = new UserEntity();
     *         user1.setId(System.currentTimeMillis() + 1);
     *         list.add(user);
     *         list.add(user1);
     *         UserMapper mapper = mapperManage.getMapper(UserMapper.class);
     *         int insertBatch = mapper.insertBatch(list);
     *         log.info("insertBatch list: {}", list);
     *         log.info("insertBatch {}", insertBatch);
     * }
     * </pre>
     *
     * @param list 实体对象列表
     * @return 受影响的行数
     */
    @Insert(BaseMapperSql.insertBatch)
    @Lang(BaseMapperDriver.class)
    @Options(useGeneratedKeys = true)
    int insertBatch(@Param(BaseMapperSql.magic_base_list) Collection<T> list);

    /**
     * 根据id进行更新
     *
     * @param entity 实体对象
     * @return 受影响的行数
     */
    @Update(BaseMapperSql.updateById)
    @Lang(BaseMapperDriver.class)
    int updateById(@Param(BaseMapperSql.magic_base_e) T entity);

    /**
     * 根据条件更新对象，可以针对无id对象实体类
     * <pre>
     * {@code
     *         UserMapper userMapper = mapperManage.getMapper(UserMapper.class);
     *         List<UserEntity> list = userMapper.selectAll();
     *         log.info("list: {}", list);
     *         UserEntity user = list.get(0);
     *         user.setUsername("lk");
     *         user.setPassword("updateByQuery");
     *         user.setNickname("update");
     *         int count = userMapper.updateByQuery(user, new Query().eq("id", user.getId()));
     *         log.info("count: {}", count);
     *         list = userMapper.selectAll();
     *         log.info("list: {}", list);
     * }
     * </pre>
     *
     * @param entity 实体对象
     * @param query  条件，比较符可以参考：{@link Condition}
     * @return 受影响的行数
     * @since 1.1.0
     */
    @Update(BaseMapperSql.updateByQuery)
    @Lang(BaseMapperDriver.class)
    int updateByQuery(@Param(BaseMapperSql.magic_base_e) T entity, @Param(BaseMapperSql.param_q) Query query);

    /**
     * 更新指定列，也能影响 {@link top.lingkang.mm.annotation.AutoUpdateTime} 注解字段
     *
     * <pre>
     * {@code
     *  int i = userMapper.updateByColumn(
     *    new UpdateColumn().set("id", 66).eq("id", 1)
     *  );
     *  System.out.println("受影响的行：" + i);
     * }
     * </pre>
     *
     * @param updateColumn 要更新的指定列，必须带上条件，因为不能调用此接口进行全量更新。
     *                     全量更新时应该调用 {@link MapperManage#createUpdate}
     * @return 受影响的行数
     * @since 1.1.0
     */
    @Update(BaseMapperSql.updateByColumn)
    @Lang(BaseMapperDriver.class)
    int updateByColumn(@Param(BaseMapperSql.param_q2) UpdateColumn updateColumn);

    /**
     * 根据主键id删除
     *
     * @param id 主键id、实体对象类
     * @return 受影响的行数
     */
    @Delete(BaseMapperSql.deleteById)
    @Lang(BaseMapperDriver.class)
    int deleteById(@Param(BaseMapperSql.param_id) Object id);

    /**
     * 根据主键id删除多行数据
     *
     * <pre>
     * {@code
     * int deleteInIds = userMapper.deleteInIds(Arrays.asList("1", "19951219"));
     * log.info("deleteInIds: {}", deleteInIds);
     * }
     * </pre>
     *
     * @param ids id数组，并非entity实体对象，参入应该是 int、String、Date等类型数组值
     * @return 受影响的行数
     * @since 1.1.0
     */
    @Delete(BaseMapperSql.deleteInIds)
    @Lang(BaseMapperDriver.class)
    int deleteInIds(@Param(BaseMapperSql.param_id_2) Collection<?> ids);

    /**
     * 根据查询条件删除数据，可以针对无id对象实体类
     * <pre>
     * {@code
     *         UserMapper mapper = mapperManage.getMapper(UserMapper.class);
     *         int count = mapper.deleteByQuery(new Query().eq("id", 1));
     *         System.out.println(count);
     * }
     * </pre>
     *
     * @param query 删除条件，比较符可以参考：{@link Condition}
     * @return 受影响的行数
     * @since 1.1.0
     */
    @Delete(BaseMapperSql.deleteByQuery)
    @Lang(BaseMapperDriver.class)
    int deleteByQuery(@Param(BaseMapperSql.param_q) Query query);

    /**
     * 插入或更新数据，不存在时插入，存在时更新
     * <pre>
     * {@code
     *  UserEntity entity = new UserEntity();
     *  entity.setId(1234566L);
     *  int insert = userMapper.insertOrUpdate(entity);
     *  System.out.println("受影响的行：" + insert);
     * }
     * </pre>
     *
     * @param entity 实体对象
     * @return 受影响的行数
     * @since 1.1.0
     */
    default int insertOrUpdate(T entity) {
        if (existsByEntity(entity))
            return updateById(entity);
        else
            return insert(entity);
    }
}
